package prettyprolog.engine;

import java.util.Vector;

import prettyprolog.datatypes.Substitution;
import prettyprolog.datatypes.Variable;

public class Domain  {

    public static Vector<Variable> domini;

/*    public Domain() {
        domini = new Vector<Variable>();
    }
*/

    public Domain() {
        this(new Vector<Variable>());
    }

    public Domain(Vector<Variable> v) {
        domini = new Vector<Variable> (v);
    }

    public static boolean isDomain(Variable s) {
        return domini.contains(s);
    }
    
    public static void update (Vector newdom) {
    	domini.removeAllElements();
    	domini.addAll(newdom);
    }

    public static int min(Variable s) {
        Vector temp = new Vector();
        int min = 0;
        if ((s instanceof Variable) && (domini.contains(s))) {
            int index = domini.indexOf(s);
//            temp = ((Variable) (domini.get(index))).dom;
            temp = Domain.getDomain(s);
            if (!temp.isEmpty())
                min = (Integer) temp.elementAt(0);
        }
        return min;
    }

    public static int max(Variable s) {
        Vector temp = new Vector();
        int max = 0;
        if ((s instanceof Variable) && (domini.contains(s))) {
            int index = domini.indexOf(s);
//            temp = ((Variable) (domini.get(index))).dom;
            temp = Domain.getDomain(s);
            if (!temp.isEmpty())
                max = (Integer) temp.elementAt(temp.size()-1);
        }
        return max;
    }

    public static void insertDomain (Variable s) {
        s.dom= new Vector();
        domini.addElement(s);
    }

    public static void deleteDomain (Variable s) {
        if ((s instanceof Variable) && (domini.contains(s))) {
            int index = domini.indexOf(s);
            domini.remove(index);
        }
    }

    public static Vector getDomain (Variable s) {
        Vector temp = new Vector();
        if ((s instanceof Variable) && (domini.contains(s))) {
            int index = domini.indexOf(s);
            temp = ((Variable) (domini.get(index))).dom;
        }
        return temp;
    }

    public static void cleanDomain() {
        if (!domini.isEmpty()) {
            domini.removeAllElements();
        }
    }
    
    public static void cleanAllDomain() {
    	if(!domini.isEmpty()) {
        	for(int i=0; i < domini.size(); i++) {
        		Vector temp = new Vector();
        		((Variable) domini.get(i)).dom.clear();
        	}
    	}
    }

    public static void updateDomain (Variable s, Vector v) {
        insort(v);
        if ((s instanceof Variable) && (domini.contains(s))) {
            int index = domini.indexOf(s);
            s.dom = v;
            domini.set(index, s);
        }
    }

    public static void setDomain (Variable s, int min, int max) {
        if ((s instanceof Variable) && (domini.contains(s))) {
            int index = domini.indexOf(s);
            s.deleteDomain();
            s.dom = domainVar(s, min, max);
            domini.set(index, s);
        }
    }

     public static Vector domainVar(Variable s, int n, int m) {
         if (n < m) {
         for (Integer i=n; i<= m; i++) {
             addEl(s.dom, i);
         }
         } else {
             for (Integer i=m; i<= n; i++) {
                 addEl(s.dom, i);
             }
         }
         return s.dom;
     }
     
     public static void newdomain (Engine e, Variable v, Substitution subst, int n, int m) {
//    	 e.getIOManager().output1("Var newdomain: "+v.toString()+"\n");
    	 Vector domain = new Vector();
    	 Vector misto = new Vector();
    	 Vector newdomain = new Vector();
    	 int index = domini.indexOf(v);
    	 if (n < m) {
    		for(Integer i= n; i <= m; i++) {
    			domain.add(i);
    			misto.add(i);
    		}    		
    		for(int j=0; j < v.dom.size(); j++) {
    			misto.add(v.dom.get(j));
    		}
    		for(int i=0; i < misto.size(); i++) {
    			if(!v.domainEmpty()) {
    				if(domain.contains(misto.get(i)) && v.dom.contains(misto.get(i)) && !newdomain.contains(misto.get(i))) {
        				newdomain.add(misto.get(i));
        			}
    			} else {
    				if(domain.contains(misto.get(i)) && !newdomain.contains(misto.get(i))) {
        				newdomain.add(misto.get(i));
        			}
    			}
    		}
    	 } else {
     		for(Integer i= m; i <= n; i++) {
    			domain.add(i);
    			misto.add(i);
    		}    		
    		for(int j=0; j < v.dom.size(); j++) {
    			misto.add(v.dom.get(j));
    		}
    		for(int i=0; i < misto.size(); i++) {
    			if(!v.domainEmpty()) {
    				if(domain.contains(misto.get(i)) && v.dom.contains(misto.get(i)) && !newdomain.contains(misto.get(i))) {
        				newdomain.add(misto.get(i));
        			}
    			} else {
    				if(domain.contains(misto.get(i)) && !newdomain.contains(misto.get(i))) {
        				newdomain.add(misto.get(i));
        			}
    			}
    		}
    	 }
    	 insort(newdomain);
    	 v.dom = newdomain;
    	 Domain.updateDomain(v, newdomain);
//    	 ((Variable) subst.getSubst(v)).dom = newdomain;
    	 if(!domini.contains(v)) {
    		 domini.add(v);
    	 } else {
    		 domini.set(index, v); 
    	 }  
     }

     public static void addEl(Vector value, Integer a) {
         value.addElement(a);
         insort(value);
     }
     
     public String toString() {
    	 String dom = "";
    	 for(Variable v : domini) {
    		 if(!v.getVariable().toString().startsWith("_")) {
    			 dom += v.getVariable().toString()+ " in "+ v.getDomain().toString()+" ";
    		 }
    	 }
    	 return dom;
    	 
     }

     private static void insort (Vector A) {
         int size2= A.size();
         for(int i=1; i < size2; i++) {
             Integer k= (Integer) A.elementAt(i);
             Integer p= i;
             while (p>0 && ((Integer) A.elementAt(p-1)).compareTo(k)>0) {
                 A.setElementAt(A.elementAt(p-1), p);
                 p=p-1;
             }
             A.setElementAt(k,p);
         }
     }

}